<template>
	<view class="">
		<view
			class="u-sticky-wrap"
			:class="[elClass]"
			:style="{
				height: fixed ? height + 'px' : 'auto',
				backgroundColor: bgColor
			}"
		>
			<view
				class="u-sticky"
				:style="{
					position: fixed ? 'fixed' : 'static',
					top: stickyTop + 'px',
					left: left + 'px',
					width: width == 'auto' ? 'auto' : width + 'px',
					zIndex: uZIndex
				}"
			>
				<slot></slot>
			</view>
		</view>
	</view>
</template>

<script>
/**
 * sticky 吸顶
 * @description 该组件与CSS中position: sticky属性实现的效果一致，当组件达到预设的到顶部距离时， 就会固定在指定位置，组件位置大于预设的顶部距离时，会重新按照正常的布局排列。
 * @tutorial https://www.uviewui.com/components/sticky.html
 * @property {String Number} offset-top 吸顶时与顶部的距离，单位rpx（默认0）
 * @property {String Number} index 自定义标识，用于区分是哪一个组件
 * @property {Boolean} enable 是否开启吸顶功能（默认true）
 * @property {String} bg-color 组件背景颜色（默认#ffffff）
 * @property {String Number} z-index 吸顶时的z-index值（默认970）
 * @property {String Number} h5-nav-height 导航栏高度，自定义导航栏时(无导航栏时需设置为0)，需要传入此值，单位px（默认44）
 * @event {Function} fixed 组件吸顶时触发
 * @event {Function} unfixed 组件取消吸顶时触发
 * @example <u-sticky offset-top="200"><view>塞下秋来风景异，衡阳雁去无留意</view></u-sticky>
 */
export default {
	name: 'u-sticky',
	props: {
		// 是否使用px
		isPxNum: {
			type: Number,
			default: 0
		},
		// 吸顶容器到顶部某个距离的时候，进行吸顶，在H5平台，NavigationBar为44px
		offsetTop: {
			type: [Number, String],
			default: 0
		},
		//列表中的索引值
		index: {
			type: [Number, String],
			default: ''
		},
		// 是否开启吸顶功能
		enable: {
			type: Boolean,
			default: true
		},
		// h5顶部导航栏的高度
		h5NavHeight: {
			type: [Number, String],
			default: 44
		},
		// 吸顶区域的背景颜色
		bgColor: {
			type: String,
			default: '#ffffff'
		},
		// z-index值
		zIndex: {
			type: [Number, String],
			default: ''
		}
	},
	data() {
		return {
			fixed: false,
			height: 'auto',
			stickyTop: 0,
			elClass: this.$u.guid(),
			left: 0,
			width: 'auto'
		};
	},
	watch: {
		offsetTop(val) {
			this.initObserver();
		},
		enable(val) {
			if (val == false) {
				this.fixed = false;
				this.disconnectObserver('contentObserver');
			} else {
				this.initObserver();
			}
		}
	},
	computed: {
		uZIndex() {
			return this.zIndex ? this.zIndex : this.$u.zIndex.sticky;
		}
	},
	mounted() {
		this.initObserver();
	},
	methods: {
		initObserver() {
			if (!this.enable) return;

			// #ifdef H5
			this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) + this.h5NavHeight : this.h5NavHeight;
			// #endif
			// #ifndef H5
			this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) : 0;
			// #endif
			if (this.isPxNum) {
				this.stickyTop = this.isPxNum;
			}
			this.disconnectObserver('contentObserver');
			this.$uGetRect('.' + this.elClass).then(res => {
				this.height = res.height;
				this.left = res.left;
				this.width = res.width;
				this.$nextTick(() => {
					this.observeContent();
				});
			});
		},
		observeContent() {
			this.disconnectObserver('contentObserver');
			const contentObserver = this.createIntersectionObserver({
				thresholds: [0.95, 0.98, 1]
			});
			contentObserver.relativeToViewport({
				top: -this.stickyTop
			});
			contentObserver.observe('.' + this.elClass, res => {
				if (!this.enable) return;
				this.setFixed(res.boundingClientRect.top);
			});
			this.contentObserver = contentObserver;
		},
		setFixed(top) {
			const fixed = top < this.stickyTop;
			if (fixed) this.$emit('fixed', this.index);
			else if (this.fixed) this.$emit('unfixed', this.index);
			this.fixed = fixed;
		},
		disconnectObserver(observerName) {
			const observer = this[observerName];
			observer && observer.disconnect();
		}
	},
	beforeDestroy() {
		this.disconnectObserver('contentObserver');
	}
};
</script>

<style scoped lang="scss">
@import '../../libs/css/style.components.scss';

.u-sticky {
	z-index: 9999999999;
}
</style>
